package com.hdsx.abatis.dao.db;

/***********************************************************************
 * Module:  DBConfiguration.java
 * Author:  kemi
 * Purpose: Defines the Class DBConfiguration
 ***********************************************************************/

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import android.content.Context;
import android.os.Environment;
import android.util.Xml;

// TODO: Auto-generated Javadoc

/**
 * The Class DBConfiguration.
 */
public class DBConfiguration {
	/** android上下文. */
	private Context context;
	/** 数据文件路径. */
	private String db_file_path;
	
	/** 数据库版本号. */
	private int db_version;

	/** 相关关联的类对象. */
	private Map<String, Class<?>> typeAliases=new HashMap<String, Class<?>>();

	/** sql对象列表. */
	private Map<String, SqlSet> sqlSets = new HashMap<String, SqlSet>();

	/** The mapper str. */
	private StringBuffer mapperStr=new StringBuffer();
	/**
	 * 解析SqlMapConfig文件.
	 *
	 * @param sqlMapConfigPath the sql map config path
	 */
	private void parseConfig(String sqlMapConfigPath) {
		InputStream inputStream = null;
		try {
			inputStream =context.getAssets().open(sqlMapConfigPath);
			XmlPullParser parser = Xml.newPullParser();
			parser.setInput(inputStream, "UTF-8");
			int type = parser.getEventType();
			while (type != XmlPullParser.END_DOCUMENT) {
				if (type == XmlPullParser.START_TAG) {
					if ("db_file_path".equals(parser.getName())) {
						this.db_file_path =parseDb_File_Path(parser.nextText());
					} else if ("db_version".equals(parser.getName())) {
						this.db_version = Integer.parseInt(parser.nextText());
					}
					else if ("typeAlias".equals(parser.getName())) {
						typeAliases.put(parser.getAttributeValue(null, "alias").trim(),Class.forName(parser.getAttributeValue(null, "type").trim()));
					} else if ("mapper".equals(parser.getName())) {
						mapperStr.append(parser.getAttributeValue(0)).append(";");
					}
				}
				type = parser.next();
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (XmlPullParserException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (NumberFormatException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} finally {
			if (inputStream != null) {
				try {
					inputStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * Parses the db_ file_ path.
	 *
	 * @param db_file_path the db_file_path
	 * @return the string
	 */
	private String parseDb_File_Path(String db_file_path)
	{
		if(db_file_path.contains(":"))
		{
			return db_file_path.replace("sdcard:",Environment.getExternalStorageDirectory()+"/");
		}
		else
		{
			return db_file_path;
		}
	}
	
	/**
	 * 解析Mapper文件.
	 *
	 */
	private void parseMapper() {
		if (mapperStr == null || mapperStr.equals("")) {
			return;
		}
		String[] mapperArr = mapperStr.substring(0, mapperStr.length() - 1).split(";");
		InputStream inputStream = null;
		String namespace = null;
		SqlSet sqlSet = null;
		String id=null;
		for (String mapperPath : mapperArr) {
			try {
				inputStream =context.getAssets().open(mapperPath);
				XmlPullParser parser = Xml.newPullParser();
				parser.setInput(inputStream, "UTF-8");
				int type = parser.getEventType();
				while (type != XmlPullParser.END_DOCUMENT) {
					if (type == XmlPullParser.START_TAG) {
						String tarName=parser.getName().trim();
						if ("mapper".equals(tarName)) {
							namespace = parser.getAttributeValue(null,"namespace");
						} else {
							sqlSet = new SqlSet();
							id=namespace+"."+ parser.getAttributeValue(null, "id");
							sqlSet.setId(id);
							/*如果没有指定参数类型则不处理*/
							String parameterType=parser.getAttributeValue(null,"parameterType");
							if(parameterType!=null&&!("".equals(parameterType)))
							{
							  sqlSet.setParameterType(aliasToType(parameterType.trim()));
							}
							if ("select".equals(tarName)) {
								sqlSet.setType("select");
								sqlSet.setResultType(aliasToType(parser.getAttributeValue(null,"resultType").trim()));
							} else if ("delete".equals(tarName)) {
								sqlSet.setType("delete");
							} else if ("update".equals(tarName)) {
								sqlSets.put(id,sqlSet);
							} else if ("insert".equals(tarName)) {
								sqlSet.setType("insert");
							}
							parseSql(parser.nextText(),sqlSet);
							sqlSets.put(id,sqlSet);
						}
						
					}			
					type = parser.next();
				}
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (XmlPullParserException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} catch (NumberFormatException e) {
				e.printStackTrace();
			} finally {
				if (inputStream != null) {
					try {
						inputStream.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}
	
	/**
	 * 解析sql.
	 *
	 * @param sql the sql
	 * @param sqlSet the sql set
	 */
	private void parseSql(String sql,SqlSet sqlSet)
	{
		if(sql.contains("#"))
		{
			
			String parameterName = null;
			String[] parameterSql = sql.split("#");
			List<String> parameterNames=new ArrayList<String>();
			try {
				for (int i = 0; i < parameterSql.length; i++) {
					if(i%2!=0)
					{
						parameterName = parameterSql[i];
						sql=sql.replace("#"+parameterName+"#","?");
						parameterNames.add(parameterName);
				   }
				}
							
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			}
			sqlSet.setParameterNames(parameterNames);
		}	
		if(sql.contains("$"))
		{
			
			String attributeName = null;
			String[] parameterSql = sql.split("\\$");
			List<String> attributeNames=new ArrayList<String>();
			try {
				int j=0;
				for (int i = 0; i < parameterSql.length; i++) {
					if(i%2!=0)
					{
						attributeName = parameterSql[i];	
						sql=sql.replace("$"+attributeName+"$","{"+j+"}");
						attributeNames.add(attributeName);
						j++;
				   }
				}
							
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			}
			sqlSet.setAttributeNames(attributeNames);
		}	
		sqlSet.setSql(sql.replaceAll("\n",""));	
	}
   
   /**
    * 将简称转化为完整类路径.
    *
    * @param alias the alias
    * @return the string
    */
	@SuppressWarnings("rawtypes")
	private Class aliasToType(String alias)
	{
		if("map".equals(alias))
		{
			return HashMap.class;
		}
		else if("int".equals(alias))
		{
			return Integer.class;
		}
		else if("string".equals(alias))
		{
			return String.class;
		}
		else
		{
			return typeAliases.get(alias);
		}
	}
	
	/**
	 * 构造函数.
	 *
	 * @param context the context
	 * @param sqlMapConfigPath the sql map config path
	 */
	public DBConfiguration(Context context, String sqlMapConfigPath) {
		this.context = context;
		parseConfig(sqlMapConfigPath);
		parseMapper();		
	}

	/**
	 * Gets the context.
	 *
	 * @return the context
	 */
	public Context getContext() {
		return context;
	}

	/**
	 * Gets the db_file_path.
	 *
	 * @return the db_file_path
	 */
	public String getDb_file_path() {
		return db_file_path;
	}

	/**
	 * Gets the db_version.
	 *
	 * @return the db_version
	 */
	public int getDb_version() {
		return db_version;
	}

	/**
	 * Gets the sql sets.
	 *
	 * @return the sql sets
	 */
	public Map<String, SqlSet> getSqlSets() {
		return sqlSets;
	}	
	
}